home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / oldwish / old / wishCmd.c < prev    next >
Encoding:
C/C++ Source or Header  |  1988-10-03  |  53.4 KB  |  2,059 lines

  1. /* 
  2.  * fsflatCmd.c --
  3.  *
  4.  *    Commands for fsflat.
  5.  *
  6.  * Copyright 1987 Regents of the University of California
  7.  * All rights reserved.
  8.  * Permission to use, copy, modify, and distribute this
  9.  * software and its documentation for any purpose and without
  10.  * fee is hereby granted, provided that the above copyright
  11.  * notice appear in all copies.  The University of California
  12.  * makes no representations about the suitability of this
  13.  * software for any purpose.  It is provided "as is" without
  14.  * express or implied warranty.
  15.  */
  16.  
  17. #ifndef lint
  18. static char rcsid[] = "$Header: fsflatCmd.c,v 1.1 88/10/03 12:45:42 mlgray Exp $ SPRITE (Berkeley)";
  19. #endif not lint
  20.  
  21. #include <sys/types.h>
  22. #include <sys/stat.h>
  23. #include "sx.h"
  24. #include "util.h"
  25. typedef    int    Boolean;
  26. #define    FALSE    0
  27. #define    TRUE    1
  28. #include "monitorClient.h"
  29. #include "fsflatInt.h"
  30.  
  31. /*
  32.  * Range of chars for which the standard insert binding is to be used,
  33.  * unless overridden by something else.
  34.  */
  35. static    char    insertFirst = 040;
  36. static    char    insertLast = 0176;
  37.  
  38.  
  39.  
  40. /*
  41.  *----------------------------------------------------------------------
  42.  *
  43.  * FsflatBindCmd --
  44.  *
  45.  *    Create (or replace or delete) a keystroke binding.  I should change
  46.  *    this to match mx so that a missing command argument means to return
  47.  *    the enumeration of the bindings with the prefix, rather than to
  48.  *    delete the binding.
  49.  *
  50.  * Syntax:
  51.  *    bind sequence [command]
  52.  *
  53.  * Results:
  54.  *    Returns TCL results.
  55.  *
  56.  * Side effects:
  57.  *    A new keystroke binding gets added to or deleted from the
  58.  *    window's command table.
  59.  *
  60.  *----------------------------------------------------------------------
  61.  */
  62. int
  63. FsflatBindCmd(aWindow, interp, argc, argv)
  64.     FsflatWindow    *aWindow;
  65.     Tcl_Interp        *interp;
  66.     int            argc;
  67.     char        **argv;
  68. {
  69.     if ((argc != 3) && (argc != 2)) {
  70.     sprintf(interp->result, "%s should be \"%.50s [sequence [command]]\"",
  71.         "wrong number of args:", argv[0]);
  72.     return TCL_ERROR;
  73.     }
  74.     if (argc == 3) {
  75.     Cmd_BindingCreate(aWindow->cmdTable, argv[1], argv[2]);
  76.     } else {
  77.     Cmd_BindingDelete(aWindow->cmdTable, argv[1]);
  78.     }
  79.     return TCL_OK;
  80. }
  81.  
  82.  
  83. /*
  84.  *----------------------------------------------------------------------
  85.  *
  86.  * FsflatChangeDirCmd --
  87.  *
  88.  *    Change the directory of the display.  Force associated shell
  89.  *    window(s) to update current directory also.
  90.  *
  91.  * Syntax:
  92.  *    changeDirectory dirName
  93.  *
  94.  * Results:
  95.  *    Returns TCL_OK if all went well, or various TCL errors if not.
  96.  *
  97.  * Side effects:
  98.  *    Current directory changes.
  99.  *
  100.  *----------------------------------------------------------------------
  101.  */
  102. int
  103. FsflatChangeDirCmd(aWindow, interp, argc, argv)
  104.     FsflatWindow    *aWindow;
  105.     Tcl_Interp        *interp;
  106.     int            argc;
  107.     char        **argv;
  108. {
  109.     struct    stat    dirAtts;
  110.     char        *newDir;
  111.  
  112.     if (argc != 2) {
  113.     sprintf(interp->result, "%s \"%.50s dirName\"",
  114.         "wrong # args: should be", argv[0]);
  115.     return TCL_ERROR;
  116.     }
  117.     if ((newDir = Util_CanonicalDir(argv[1], aWindow->dir, (char *) NULL))
  118.         == NULL) {
  119.     sprintf(interp->result,
  120.         "Couldn't figure out directory name %s.", argv[1]);
  121.     return TCL_ERROR;
  122.     }
  123.     /* Check the validity of the new dir. */
  124.     if (lstat(newDir, &dirAtts) != 0) {
  125.     sprintf(interp->result,
  126.         "Cannot switch to dir %s.  Maybe it doesn't exist?", newDir);
  127.     free(newDir);
  128.     return TCL_ERROR;    /* should above message be passed to routine? */
  129.     }
  130.     if ((dirAtts.st_mode & S_IFMT) != S_IFDIR) {    /* not a directory */
  131.     sprintf(interp->result, "%s is not a directory.", newDir);
  132.     free(newDir);
  133.     return TCL_ERROR;    /* should above message be passed to routine? */
  134.     }
  135.     FsflatChangeDir(aWindow, newDir);    /* does everything */
  136.     free(newDir);
  137.  
  138.     return TCL_OK;
  139. }
  140.  
  141.  
  142. /*
  143.  *----------------------------------------------------------------------
  144.  *
  145.  * FsflatChangeFieldsCmd --
  146.  *
  147.  *    Change the method of sorting directory entries.
  148.  *
  149.  * Syntax:
  150.  *    changeFields [fields]
  151.  *
  152.  * Results:
  153.  *    Returns TCL_OK if all went well, or TCL errors if not.
  154.  *
  155.  * Side effects:
  156.  *    The fields displayed for each file will change.  The user will be
  157.  *    prompted to see if he wishes to make the new sorting method the
  158.  *    default method for the directory.
  159.  *
  160.  *----------------------------------------------------------------------
  161.  */
  162. int
  163. FsflatChangeFieldsCmd(aWindow, interp, argc, argv)
  164.     FsflatWindow    *aWindow;
  165.     Tcl_Interp        *interp;
  166.     int            argc;
  167.     char        **argv;
  168. {
  169.     int    which;
  170.     int    length;
  171.     int    arg;
  172.  
  173.     /*
  174.      * any number of args may be okay here, depending on how many fields they
  175.      * wish to display.
  176.      */
  177.     aWindow->displayInstructions = 0;
  178.     if (argc > 1) {
  179.     for (arg = 1; arg < argc; arg++) {
  180.         length = strlen(argv[arg]);
  181.         if (strncmp(argv[arg], "name", length) == 0 ||
  182.             strncmp(argv[arg], "Name", length) == 0) { /* default */
  183.         continue;
  184.         }
  185.         /*
  186.          * atime = access time = time file data last read or modified.
  187.          * ctime = desc modify time = time file status last changed, by
  188.          *        writing or inode changes.
  189.          * mtime = data modify time = time data last modified.
  190.          */
  191.  
  192.         if (strncmp(argv[arg], "size", length) == 0 ||
  193.             strncmp(argv[arg], "Size", length) == 0) {
  194.         aWindow->displayInstructions |= FSFLAT_SIZE_FIELD;
  195.         continue;
  196.         }
  197.         if (strncmp(argv[arg], "atime", length) == 0 ||
  198.             strncmp(argv[arg], "Atime", length) == 0 ||
  199.             strncmp(argv[arg], "accesstime", length) == 0 ||
  200.             strncmp(argv[arg], "accessTime", length) == 0 ||
  201.             strncmp(argv[arg], "AccessTime", length) == 0) {
  202.         aWindow->displayInstructions |= FSFLAT_ATIME_FIELD;
  203.         continue;
  204.         }
  205.         if (strncmp(argv[arg], "ctime", length) == 0 ||
  206.             strncmp(argv[arg], "Ctime", length) == 0 ||
  207.             strncmp(argv[arg], "descmodtime", length) == 0 ||
  208.             strncmp(argv[arg], "descModTime", length) == 0 ||
  209.             strncmp(argv[arg], "DescModTime", length) == 0 ||
  210.             strncmp(argv[arg], "descmodifytime", length) == 0 ||
  211.             strncmp(argv[arg], "descModifyTime", length) == 0 ||
  212.             strncmp(argv[arg], "DescModifyTime", length) == 0 ||
  213.             strncmp(argv[arg], "descriptormodifytime", length) == 0 ||
  214.             strncmp(argv[arg], "descriptorModifyTime", length) == 0 ||
  215.             strncmp(argv[arg], "DescriptorModifyTime", length) == 0) {
  216.         aWindow->displayInstructions |= FSFLAT_DTIME_FIELD;
  217.         continue;
  218.         }
  219.         if (strncmp(argv[arg], "mtime", length) == 0 ||
  220.             strncmp(argv[arg], "Mtime", length) == 0 ||
  221.             strncmp(argv[arg], "datamodtime", length) == 0 ||
  222.             strncmp(argv[arg], "dataModTime", length) == 0 ||
  223.             strncmp(argv[arg], "DataModTime", length) == 0 ||
  224.             strncmp(argv[arg], "datamodifytime", length) == 0 ||
  225.             strncmp(argv[arg], "dataModifyTime", length) == 0 ||
  226.             strncmp(argv[arg], "DataModifyTime", length) == 0) {
  227.         aWindow->displayInstructions |= FSFLAT_MTIME_FIELD;
  228.         continue;
  229.         }
  230.         sprintf(interp->result, "%s %s %s", "bad argument, the possible",
  231.             "arguments are size, atime (AccessTime),",
  232.             "mtime (DataModifyTime), and dtime (DescriptorModifyTime)");
  233.         return TCL_ERROR;
  234.     }
  235.     goto finishedFields;
  236.     }
  237.     which = Sx_Notify(fsflatDisplay, aWindow->surroundingWindow, -1, -1, 0,
  238.         "Display Size?", NULL, TRUE, "Yes", "No", "Stop",
  239.         (char *) NULL);
  240.     if (which == 0) {
  241.     aWindow->displayInstructions |= FSFLAT_SIZE_FIELD;
  242.     } else if (which == 2) {
  243.     goto finishedFields;
  244.     }
  245.     which = Sx_Notify(fsflatDisplay, aWindow->surroundingWindow, -1, -1, 0,
  246.         "Display AccessTime?", NULL, TRUE, "Yes", "No", "Stop",
  247.         (char *) NULL);
  248.     if (which == 0) {
  249.     aWindow->displayInstructions |= FSFLAT_ATIME_FIELD;
  250.     } else if (which == 2) {
  251.     goto finishedFields;
  252.     }
  253.     which = Sx_Notify(fsflatDisplay, aWindow->surroundingWindow, -1, -1, 0,
  254.         "Display DataModifyTime?", NULL, TRUE, "Yes", "No", "Stop",
  255.         (char *) NULL);
  256.     if (which == 0) {
  257.     aWindow->displayInstructions |= FSFLAT_MTIME_FIELD;
  258.     } else if (which == 2) {
  259.     goto finishedFields;
  260.     }
  261.     which = Sx_Notify(fsflatDisplay, aWindow->surroundingWindow, -1, -1, 0,
  262.         "Display DescriptorModifyTime?", NULL, TRUE, "Yes", "No",
  263.         "Stop", (char *) NULL);
  264.     if (which == 0) {
  265.     aWindow->displayInstructions |= FSFLAT_DTIME_FIELD;
  266.     } else if (which == 2) {
  267.     goto finishedFields;
  268.     }
  269. finishedFields:
  270.     ;    /* nothing */
  271.  
  272.     if (aWindow->dontDisplayChangesP == FALSE) {
  273.     /* update display */
  274.     if (aWindow->firstElement == UNINITIALIZED) {
  275.         aWindow->firstElement = 1;
  276.     }
  277.     FsflatSetPositions(aWindow);
  278.     }
  279.  
  280.     return TCL_OK;
  281. }
  282.  
  283. #ifdef NOTDEF
  284.  
  285. /*
  286.  *----------------------------------------------------------------------
  287.  *
  288.  * FsflatChangeGroupsCmd --
  289.  *
  290.  *    Change the definition of a group.
  291.  *
  292.  * Syntax:
  293.  *    changeGroups
  294.  *
  295.  * Results:
  296.  *    Returns TCL_OK if all went well, or TCL errors if not.
  297.  *    error occurred.
  298.  *
  299.  * Side effects:
  300.  *    The pattern matching rules or associated command bindings for the
  301.  *    group may change.
  302.  *
  303.  *----------------------------------------------------------------------
  304.  */
  305. int
  306. FsflatChangeGroupsCmd(aWindow, interp, argc, argv)
  307.     FsflatWindow    *aWindow;
  308.     Tcl_Interp        *interp;
  309.     int            argc;
  310.     char        **argv;
  311. {
  312.     static    int    count = 0;
  313.     FILE    *stream;
  314.     int    pid;
  315.     char    buffer[MAXPATHLEN];
  316.     char    **args;
  317.     int    pidArray[1];
  318.     FsflatGroup    *grpPtr;
  319.     int    childPid;
  320.  
  321.     if (strcmp(argv[0], "deleteGroup") == 0 ||
  322.         strcmp(argv[0], "deletegroup") == 0) {
  323.     /* delete the group and clean up */
  324.     }
  325.     if (
  326.     /*
  327.      * open a file
  328.      */
  329.     Proc_GetIDs(&pid, NULL, NULL, NULL, NULL);
  330.     sprintf(buffer, "%s%d.%d", "/tmp/tmpFsflat", pid, count);
  331.     count++;
  332.     if ((stream = fopen(buffer, "w")) == NULL) {
  333.     sprintf(interp->result, "%s %s %s",
  334.         "Couldn't open file", buffer,
  335.         "in which to let you edit the selection rules.");
  336.     return TCL_ERROR;
  337.     }
  338.     for (grpPtr = aWindow->groupList; grpPtr != NULL;
  339.         grpPtr = grpPtr->nextPtr) {
  340.     fputs("Select:\n", stream);
  341.     fputs(grpPtr->rule, stream);
  342.     fputs("\n", stream);
  343.     if (grpPtr->name != NULL) {
  344.         fputs("GroupName:\n", stream);
  345.         fputs(grpPtr->name, stream);
  346.         fputs("\n\n", stream);
  347.     }
  348.     }
  349.     fclose(stream);
  350.     /* I should be checking ferror for above PutStrings and Close return. */
  351.     /* close file and mx it. */
  352.     /* parse file when mx returns. */
  353.     if (Proc_Fork(TRUE, &childPid) == PROC_CHILD_PROC) {
  354.     /*child*/
  355.     /* what to do about this pathname? */
  356.     args = (char **) malloc(4 * sizeof (char *));
  357.     args[0] = Util_Strcpy(NULL, "mx");
  358.     args[1] = Util_Strcpy(NULL, "-D");
  359.     args[2] = Util_Strcpy(NULL, buffer);    /* CORE LEAK */
  360.     args[3] = NULL;
  361.     Proc_Exec("/sprite2/users/ouster/mx10/mx", args, FALSE);
  362.     /* error if returned. */
  363.     sprintf(fsflatErrorMsg, "Exec of %s returned.",
  364.         "/sprite2/users/oustser/mx10/mx");
  365.     Sx_Notify(fsflatDisplay, aWindow->surroundingWindow, -1, -1, 0,
  366.         fsflatErrorMsg, NULL, TRUE, "Skip command", (char *) NULL);
  367.     exit(-1);
  368.     } else {
  369.     /*parent waits */
  370.     pidArray[0] = childPid;
  371.     Proc_Wait(1, pidArray, PROC_WAIT_BLOCK, NULL, NULL, NULL, NULL, NULL);
  372.     }
  373.     if ((stream = fopen(buffer, "a")) == NULL) {
  374.     sprintf(fsflatErrorMsg, "%s %s %s",
  375.         "Couldn't open file", buffer,
  376.         "in which you edited the selection rules.");
  377.     Sx_Notify(fsflatDisplay, aWindow->surroundingWindow, -1, -1, 0,
  378.         fsflatErrorMsg, NULL, TRUE, "Skip command", (char *) NULL);
  379.     return TCL_ERROR;
  380.     }
  381.     if (aWindow->sortingInstructions & FSFLAT_ALPHA_SORT) {
  382.     if (aWindow->sortingInstructions & FSFLAT_REVERSE_SORT) {
  383.         fputs("Sort:\nAlphaReverse\n\n", stream);
  384.     } else {
  385.         fputs("Sort:\nAlpha\n\n", stream);
  386.     }
  387.     }
  388.     if (aWindow->sortingInstructions & FSFLAT_ATIME_SORT) {
  389.     if (aWindow->sortingInstructions & FSFLAT_REVERSE_SORT) {
  390.         fputs("Sort:\nAccessTimeReverse\n\n", stream);
  391.     } else {
  392.         fputs("Sort:\nAccessTime\n\n", stream);
  393.     }
  394.     }
  395.     if (aWindow->sortingInstructions & FSFLAT_MTIME_SORT) {
  396.     if (aWindow->sortingInstructions & FSFLAT_REVERSE_SORT) {
  397.         fputs("Sort:\nDataModifyTimeReverse\n\n", stream);
  398.     } else {
  399.         fputs("Sort:\nDataModifyTime\n\n", stream);
  400.     }
  401.     }
  402.     if (aWindow->sortingInstructions & FSFLAT_DTIME_SORT) {
  403.     if (aWindow->sortingInstructions & FSFLAT_REVERSE_SORT) {
  404.         fputs("Sort:\nDescriptorModifyTimeReverse\n\n", stream);
  405.     } else {
  406.         fputs("Sort:\nDescriptorModifyTime\n\n", stream);
  407.     }
  408.     }
  409.     if (aWindow->sortingInstructions & FSFLAT_SIZE_SORT) {
  410.     if (aWindow->sortingInstructions & FSFLAT_REVERSE_SORT) {
  411.         fputs("Sort:\nSizeReverse\n\n", stream);
  412.     } else {
  413.         fputs("Sort:\nSize\n\n", stream);
  414.     }
  415.     }
  416.     if (aWindow->displayInstructions & FSFLAT_NAME_FIELD) {
  417.     fputs("Display:\nName\n\n", stream);
  418.     }
  419.     if (aWindow->displayInstructions & FSFLAT_ATIME_FIELD) {
  420.     fputs("Display:\nAccessTime\n\n", stream);
  421.     }
  422.     if (aWindow->displayInstructions & FSFLAT_MTIME_FIELD) {
  423.     fputs("Display:\nDataModifyTime\n\n", stream);
  424.     }
  425.     if (aWindow->displayInstructions & FSFLAT_DTIME_FIELD) {
  426.     fputs("Display:\nDescriptorModifyTime\n\n", stream);
  427.     }
  428.     if (aWindow->displayInstructions & FSFLAT_SIZE_FIELD) {
  429.     fputs("Display:\nSize\n\n", stream);
  430.     }
  431.     fclose(stream);
  432.  
  433.     FsflatGarbageCollect(aWindow);
  434. #ifdef FUTURE
  435.     /*
  436.      * This routine was changed not to take second arg!
  437.      */
  438.     if (FsflatGatherNames(aWindow, buffer) != TCL_OK) {
  439.     return bad value and switch directories?
  440.     error string will be displayed in top-level display thingy?
  441.     }
  442. #endif FUTURE
  443.     
  444.     /* should it repick the size here if aWindow->pickSizeP is true? */
  445.     aWindow->firstElement = 1;
  446.     FsflatSetPositions(aWindow);
  447.     /* FsflatRedraw will be called from event caused in FsflatSetPositions() */
  448.  
  449.     /* ask if they want to make it permanent. */
  450.  
  451.     return TCL_OK;
  452. }
  453. #endif NOTDEF
  454.  
  455.  
  456.  
  457. /*
  458.  *----------------------------------------------------------------------
  459.  *
  460.  * FsflatChangeGroupCmd --
  461.  *
  462.  *    Change the definition of a group.
  463.  *
  464.  * Syntax:
  465.  *    changeGroup name newDefType newDef
  466.  *
  467.  * Results:
  468.  *    Returns TCL_OK if all went well, or TCL errors if not.
  469.  *
  470.  * Side effects:
  471.  *    The specified group will be changed.
  472.  *
  473.  *----------------------------------------------------------------------
  474.  */
  475. int
  476. FsflatChangeGroupCmd(aWindow, interp, argc, argv)
  477.     FsflatWindow    *aWindow;
  478.     Tcl_Interp        *interp;
  479.     int            argc;
  480.     char        **argv;
  481. {
  482.     FsflatGroup    *grpPtr;
  483.     FsflatGroup    *newGrpPtr;
  484.     FsflatGroup    *bPtr;
  485.  
  486.     if (argc != 4) {
  487.     sprintf(interp->result, "%s %s", "Wrong # of args. Must be 4 args,",
  488.         "\"changeGroup name newDefType newDef\"");
  489.     return TCL_ERROR;
  490.     }
  491.  
  492.     /* Make sure no other group already has the new definition. */
  493.     for (grpPtr = aWindow->groupList; grpPtr != NULL;
  494.         grpPtr = grpPtr->nextPtr) {
  495.     if (strcmp(argv[3], grpPtr->rule) == 0) {
  496.         if (grpPtr->fileList == NULL && aWindow->hideEmptyGroupsP) {
  497.             sprintf(interp->result, "%s %s, %s",
  498.             "A group already has the definition", argv[3],
  499.             "but it may not be visible since no files match it.");
  500.         } else {
  501.         sprintf(interp->result, "A group already has the definition %s",
  502.             argv[3]);
  503.         }
  504.         return TCL_ERROR;
  505.     }
  506.     }
  507.  
  508.     /* find group to replace */
  509.     if (aWindow->groupList == NULL) {
  510.     sprintf(interp->result,
  511.         "No groups have been defined in order to change one");
  512.     return TCL_ERROR;
  513.     }
  514.  
  515.     bPtr = NULL;
  516.     for (grpPtr = aWindow->groupList; grpPtr != NULL;
  517.         grpPtr = grpPtr->nextPtr) {
  518.     if (strcmp(argv[1], grpPtr->rule) == 0) {
  519.         break;
  520.     }
  521.     bPtr = grpPtr;
  522.     }
  523.  
  524.     if (grpPtr == NULL) {
  525.     sprintf(interp->result, "No group with that definition");
  526.     return TCL_ERROR;
  527.     }
  528.  
  529.  
  530.     newGrpPtr = (FsflatGroup *) malloc(sizeof (FsflatGroup));
  531.  
  532.     /* test the new group's definition */
  533.     if (GetNewGroup(aWindow, interp, argv + 2, newGrpPtr) != TCL_OK) {
  534.     free(newGrpPtr);
  535.     return TCL_ERROR;
  536.     }
  537.  
  538.     newGrpPtr->nextPtr = grpPtr->nextPtr;
  539.  
  540.     FsflatGarbageGroup(aWindow, grpPtr);
  541.  
  542.     if (bPtr == NULL) {
  543.     aWindow->groupList = newGrpPtr;
  544.     } else {
  545.     bPtr->nextPtr = newGrpPtr;
  546.     }
  547.     if (aWindow->dontDisplayChangesP == FALSE) {
  548.     /* update display */
  549.     if (aWindow->firstElement == UNINITIALIZED) {
  550.         aWindow->firstElement = 1;
  551.     }
  552.     FsflatSetPositions(aWindow);
  553.     }
  554.     
  555.     return TCL_OK;
  556. }
  557.  
  558.  
  559. /*
  560.  *----------------------------------------------------------------------
  561.  *
  562.  * GetNewGroup --
  563.  *
  564.  *    Initialize and collect files for a new group.
  565.  *
  566.  * Results:
  567.  *    Returns TCL_OK if all went well, or TCL errors if not.
  568.  *
  569.  * Side effects:
  570.  *    Memory will be allocated for various things.
  571.  *
  572.  *----------------------------------------------------------------------
  573.  */
  574. int
  575. GetNewGroup(aWindow, interp, argv, newGrpPtr)
  576.     FsflatWindow    *aWindow;
  577.     Tcl_Interp        *interp;
  578.     char        **argv;
  579.     FsflatGroup        *newGrpPtr;
  580. {
  581.     int        procArgc;
  582.     char    **procArgv;
  583.     int        num;
  584.  
  585.     /* parse command arguments */
  586.     if (strcmp("comparison", argv[0]) == 0) {    /* simple comp stuff */
  587.     newGrpPtr->defType = COMPARISON;
  588.     newGrpPtr->rule = Util_Strcpy((char *) NULL, argv[1]);
  589.     /* test new grp def */
  590.     if (Pattern_Match(newGrpPtr->rule, "x") < 0) {
  591.         sprintf(interp->result,
  592.             "The comparison rule {%s} contains an error",
  593.             newGrpPtr->rule);
  594.         free(newGrpPtr->rule);
  595.         return TCL_ERROR;
  596.     }
  597.     } else if (strcmp("proc", argv[0]) != 0) {    /* bad def */
  598.     sprintf(interp->result, "Bad group definition type %s", argv[0]);
  599.     return TCL_ERROR;
  600.     } else {        /* TCL proc */
  601.     newGrpPtr->defType = PROC;
  602.     /* get name of proc */
  603.     if (Tcl_SplitList(interp, argv[1], &procArgc, &procArgv) != TCL_OK) {
  604.         return TCL_ERROR;
  605.     }
  606.     newGrpPtr->rule = Util_Strcpy((char *) NULL, procArgv[1]);
  607.     if (Tcl_Eval(interp, argv[1], '\0', NULL) != TCL_OK) {
  608.         free(newGrpPtr->rule);
  609.         free(procArgv);
  610.         return TCL_ERROR;
  611.     }
  612.     /* Will this really free it?  Tcl man page says so... */
  613.     free(procArgv);
  614.  
  615.     /* test new grp def */
  616.     if (FsflatDoTclSelect(interp, newGrpPtr->rule, "x", &num) != TCL_OK) {
  617.         free(newGrpPtr->rule);
  618.         return TCL_ERROR;
  619.     }
  620.     }
  621.     newGrpPtr->nextPtr = NULL;
  622.     newGrpPtr->myColumn = UNINITIALIZED;
  623.     newGrpPtr->headerWindow = UNINITIALIZED;
  624.     newGrpPtr->x = UNINITIALIZED;
  625.     newGrpPtr->y = UNINITIALIZED;
  626.     newGrpPtr->width = 0;
  627.     newGrpPtr->height = 0;
  628.     newGrpPtr->fileList = NULL;
  629.     newGrpPtr->groupBindings = NULL;
  630.     newGrpPtr->selectedP = FALSE;
  631.     newGrpPtr->highlightP = FALSE;
  632.     /*
  633.      * If this is too slow, then change this so it does not actually
  634.      * gather the files?
  635.      */
  636.     if (FsflatGatherSingleGroup(aWindow, newGrpPtr) != TCL_OK) {
  637.     /* eliminate group definition? */
  638.     free(newGrpPtr->rule);
  639.     return TCL_ERROR;
  640.     }
  641.  
  642.     return TCL_OK;
  643. }
  644.  
  645.  
  646. /*
  647.  *----------------------------------------------------------------------
  648.  *
  649.  * FsflatPrintTclError --
  650.  *
  651.  *    Print out a tcl interpreter error message.
  652.  *
  653.  * Results:
  654.  *    None.
  655.  *
  656.  * Side effects:
  657.  *    None.
  658.  *
  659.  *----------------------------------------------------------------------
  660.  */
  661. void
  662. FsflatPrintTclError(aWindow)
  663.     FsflatWindow    *aWindow;
  664. {
  665.     char    c;
  666.  
  667.     /*
  668.      * Capitalize first character of error message.
  669.      */
  670.     c = aWindow->interp->result[0];
  671.     if ((c >= 'a') && (c <= 'z')) {
  672.     aWindow->interp->result[0] += 'A' - 'a';
  673.     }
  674.     /*
  675.      * output message - should call routine that uses 1-line window
  676.      * if possible.
  677.      */
  678.     Sx_Notify(fsflatDisplay, aWindow->surroundingWindow, -1, -1, 0,
  679.         aWindow->interp->result, NULL, TRUE, "Continue", (char *) NULL);
  680.     /* replace lower case */
  681.     aWindow->interp->result[0] = c;
  682.  
  683.     return;
  684. }
  685.  
  686.  
  687. /*
  688.  *----------------------------------------------------------------------
  689.  *
  690.  * FsflatDefineGroupCmd --
  691.  *
  692.  *    Add the definition of a new group.
  693.  *    Currently, this only will add it to the end of the list of groups.
  694.  *
  695.  * Syntax:
  696.  *    defineGroup defType def
  697.  *
  698.  * Results:
  699.  *    Returns TCL_OK if all went well, or TCL errors if not.
  700.  *
  701.  * Side effects:
  702.  *    A new group will be added.  It will not be displayed until something
  703.  *    causes a redisplay.
  704.  *
  705.  *----------------------------------------------------------------------
  706.  */
  707. int
  708. FsflatDefineGroupCmd(aWindow, interp, argc, argv)
  709.     FsflatWindow    *aWindow;
  710.     Tcl_Interp        *interp;
  711.     int            argc;
  712.     char        **argv;
  713. {
  714.     FsflatGroup    *grpPtr;
  715.     FsflatGroup    *newGrpPtr;
  716.  
  717.     if (argc != 3) {
  718.     sprintf(interp->result, "%s %s", "Wrong # of args. Must be 3 args,",
  719.         "\"defineGroup defType def\"");
  720.     return TCL_ERROR;
  721.     }
  722.  
  723.     for (grpPtr = aWindow->groupList; grpPtr != NULL;
  724.         grpPtr = grpPtr->nextPtr) {
  725.     if (strcmp(argv[2], grpPtr->rule) == 0) {
  726.         if (grpPtr->fileList == NULL && aWindow->hideEmptyGroupsP) {
  727.             sprintf(interp->result, "%s %s, %s",
  728.             "A group already has the definition", argv[2],
  729.             "but it may not be visible since no files match it.");
  730.         } else {
  731.         sprintf(interp->result, "A group already has the definition %s",
  732.             argv[2]);
  733.         }
  734.         return TCL_ERROR;
  735.     }
  736.     }
  737.  
  738.     newGrpPtr = (FsflatGroup *) malloc(sizeof (FsflatGroup));
  739.  
  740.     /* test the new group's definition */
  741.     if (GetNewGroup(aWindow, interp, argv + 1, newGrpPtr) != TCL_OK) {
  742.     free(newGrpPtr);
  743.     FsflatPrintTclError(aWindow);
  744.     FsflatDoCmd(aWindow, "close");
  745.     /*
  746.      * It seems weird to return with TCL_ERROR here, but if i don't,
  747.      * something will try to unmap the previously destroyed window.
  748.      * Strangely, nothing wrong seems to happen this way, such as
  749.      * something trying to print out a message in a deleted interpreter...
  750.      */
  751.     return TCL_ERROR;
  752.     }
  753.  
  754.     /* attach new group to end of list */
  755.     if (aWindow->groupList == NULL) {
  756.     aWindow->groupList = newGrpPtr;
  757.     } else {
  758.     for (grpPtr = aWindow->groupList; grpPtr->nextPtr != NULL;
  759.         grpPtr = grpPtr->nextPtr) {
  760.         /* nothing */
  761.     }
  762.     grpPtr->nextPtr = newGrpPtr;
  763.     }
  764.     if (aWindow->dontDisplayChangesP == FALSE) {
  765.     /* update display */
  766.     if (aWindow->firstElement == UNINITIALIZED) {
  767.         aWindow->firstElement = 1;
  768.     }
  769.     FsflatSetPositions(aWindow);
  770.     }
  771.     return TCL_OK;
  772. }
  773.  
  774.  
  775. /*
  776.  *----------------------------------------------------------------------
  777.  *
  778.  * FsflatSelectionCmd --
  779.  *
  780.  *    Return the current value of the selection set in interp->result.
  781.  *
  782.  * Syntax:
  783.  *    selection
  784.  *
  785.  * Results:
  786.  *    Returns TCL_OK if all went well, or TCL_ERROR if any sort of
  787.  *    error occurred.
  788.  *
  789.  * Side effects:
  790.  *    None except memory allocation.
  791.  *
  792.  *----------------------------------------------------------------------
  793.  */
  794. /*ARGSUSED*/
  795. int
  796. FsflatSelectionCmd(aWindow, interp, argc, argv)
  797.     FsflatWindow    *aWindow;
  798.     Tcl_Interp        *interp;
  799.     int            argc;
  800.     char        **argv;
  801. {
  802.     if (argc > 1) {
  803.     sprintf(interp->result, "Too many args to selection command.");
  804.     return TCL_ERROR;
  805.     }
  806.     return TCL_OK;
  807. }
  808.  
  809.  
  810. /*
  811.  *----------------------------------------------------------------------
  812.  *
  813.  * FsflatSortFilesCmd --
  814.  *
  815.  *    Add or change the method of sorting directory entries.
  816.  *
  817.  * Syntax:
  818.  *    changeSort [method]
  819.  *
  820.  * Results:
  821.  *    Returns TCL_OK if all went well, or TCL_ERROR if any sort of
  822.  *    error occurred.
  823.  *
  824.  * Side effects:
  825.  *    The order of the files displayed will change if the new sorting
  826.  *    method is different.  In this case, the user will be prompted
  827.  *    to see if he wishes to make the new sorting method the default
  828.  *    method for the directory.
  829.  *
  830.  *----------------------------------------------------------------------
  831.  */
  832. int
  833. FsflatSortFilesCmd(aWindow, interp, argc, argv)
  834.     FsflatWindow    *aWindow;
  835.     Tcl_Interp        *interp;
  836.     int            argc;
  837.     char        **argv;
  838. {
  839.     int    which;
  840.  
  841.     if (argc > 3) {
  842.     sprintf(interp->result, "Too many args: 3 arg maximum to sort command");
  843.     return TCL_ERROR;
  844.     }
  845.     if (argc == 1) {
  846.     /*
  847.      * Get the sorting method from the user.  It would be nice if this
  848.      * could all be in one notifier or in a check-list like window, but
  849.      * Sx_Notify puts all the buttons in a single line at the top of the
  850.      * notifier and there are too many buttons to fit on the window here
  851.      * if the "reverse" options are included.  So for now it's done with
  852.      * 2 notifiers, one to get what to sort by and the next to say
  853.      * forwards or backwards.
  854.      */
  855.     which = Sx_Notify(fsflatDisplay, aWindow->surroundingWindow, -1, -1, 0,
  856.         "Pick sorting method", NULL, TRUE, "Alpha", "AccessTime",
  857.         "DataModifyTime", "DescriptorModifyTime", "Size",
  858.         (char *) NULL);
  859.     switch(which) {
  860.     case 0:
  861.         aWindow->sortingInstructions = FSFLAT_ALPHA_SORT;
  862.         break;
  863.     case 1:
  864.         aWindow->sortingInstructions = FSFLAT_ATIME_SORT;
  865.         break;
  866.     case 2:
  867.         aWindow->sortingInstructions = FSFLAT_MTIME_SORT;
  868.         break;
  869.     case 3:
  870.         aWindow->sortingInstructions = FSFLAT_DTIME_SORT;
  871.         break;
  872.     case 4:
  873.         aWindow->sortingInstructions = FSFLAT_SIZE_SORT;
  874.         break;
  875.     default:
  876.         sprintf(fsflatErrorMsg, "%s %s", "Something is wrong.",
  877.             "The sorthing method just entered is unrecognized.");
  878.         Sx_Notify(fsflatDisplay, aWindow->surroundingWindow, -1, -1, 0,
  879.             fsflatErrorMsg, "Skip command", (char *) NULL);
  880.         return TCL_ERROR;
  881.     }
  882.     which = Sx_Notify(fsflatDisplay, aWindow->surroundingWindow, -1, -1, 0,
  883.         "Sort in forwards or reverse order?", NULL, TRUE,
  884.         "Forwards", "Reverse", (char *) NULL);
  885.     if (which == 1) {
  886.         aWindow->sortingInstructions |= FSFLAT_REVERSE_SORT;
  887.     }
  888.     FsflatSetSort(aWindow, NULL, NULL);
  889.     } else if (argc == 2) {        /* parse command */
  890.     FsflatSetSort(aWindow, argv[1], NULL);
  891.     } else {
  892.     FsflatSetSort(aWindow, argv[1], argv[2]);
  893.     }
  894.     /*
  895.      * Now ask if they want to make this change be the default sort
  896.      * method for this directory.
  897.      */
  898.     /* soon. */
  899.  
  900.     if (aWindow->dontDisplayChangesP == FALSE) {
  901.     /* update display */
  902.     if (aWindow->firstElement == UNINITIALIZED) {
  903.         aWindow->firstElement = 1;
  904.     }
  905.     FsflatSetPositions(aWindow);
  906.     }
  907.  
  908.     return TCL_OK;
  909. }
  910.  
  911.  
  912. /*
  913.  *----------------------------------------------------------------------
  914.  *
  915.  * FsflatSetSort --
  916.  *
  917.  *    Change the sorting information and resort files.
  918.  *    If the reverse argument is non-null, do the reverse sort of the
  919.  *    sortMethod argument.  If the sortMethod argument is NULL, then the
  920.  *    aWindow->sortingInstructions field is already set.
  921.  *
  922.  * Results:
  923.  *    None.
  924.  *
  925.  * Side effects:
  926.  *    The order of the files displayed will change if the new sorting
  927.  *    method is different.
  928.  *
  929.  *----------------------------------------------------------------------
  930.  */
  931. void
  932. FsflatSetSort(aWindow, sortMethod, reverse)
  933.     FsflatWindow    *aWindow;
  934.     char        *sortMethod;
  935.     char        *reverse;
  936. {
  937.     int        getAttrsP = FALSE;
  938.     FsflatFile    *tmpPtr;
  939.     FsflatGroup    *grpPtr;
  940.     int        (*compareProc)();
  941.     FsflatFile    **fileArray;
  942.     int        i, arraySize;
  943.  
  944.     if (sortMethod != NULL) {
  945.     aWindow->sortingInstructions = 0;
  946.     if (reverse != NULL) {
  947.         aWindow->sortingInstructions |= FSFLAT_REVERSE_SORT;
  948.     }
  949.     if (strcmp(sortMethod, "alpha") == 0 ||
  950.         strcmp(sortMethod, "Alpha") == 0) {
  951.         aWindow->sortingInstructions |= FSFLAT_ALPHA_SORT;
  952.     }
  953.     if (strcmp(sortMethod, "accessTime") == 0 ||
  954.         strcmp(sortMethod, "AccessTime") == 0 ||
  955.         strcmp(sortMethod, "atime") == 0 ||
  956.         strcmp(sortMethod, "aTime") == 0 ||
  957.         strcmp(sortMethod, "Atime") == 0) {
  958.         aWindow->sortingInstructions |= FSFLAT_ATIME_SORT;
  959.     }
  960.     if (strcmp(sortMethod, "modifyTime") == 0 ||
  961.         strcmp(sortMethod, "ModifyTime") == 0 ||
  962.         strcmp(sortMethod, "datamodtime") == 0 ||
  963.         strcmp(sortMethod, "dataModTime") == 0 ||
  964.         strcmp(sortMethod, "DataModTime") == 0 ||
  965.         strcmp(sortMethod, "datamodifytime") == 0 ||
  966.         strcmp(sortMethod, "dataModifyTime") == 0 ||
  967.         strcmp(sortMethod, "DataModifyTime") == 0 ||
  968.         strcmp(sortMethod, "mtime") == 0 ||
  969.         strcmp(sortMethod, "mTime") == 0 ||
  970.         strcmp(sortMethod, "Mtime") == 0) {
  971.         aWindow->sortingInstructions |= FSFLAT_MTIME_SORT;
  972.     }
  973.     if (strcmp(sortMethod, "descModifyTime") == 0 ||
  974.         strcmp(sortMethod, "DescModifyTime") == 0 ||
  975.         strcmp(sortMethod, "descmodifytime") == 0 ||
  976.         strcmp(sortMethod, "descmodtime") == 0 ||
  977.         strcmp(sortMethod, "descModTime") == 0 ||
  978.         strcmp(sortMethod, "DescModTime") == 0 ||
  979.         strcmp(sortMethod, "descriptormodifytime") == 0 ||
  980.         strcmp(sortMethod, "descriptorModifyTime") == 0 ||
  981.         strcmp(sortMethod, "DescriptorModifyTime") == 0 ||
  982.         strcmp(sortMethod, "dtime") == 0 ||
  983.         strcmp(sortMethod, "dTime") == 0 ||
  984.         strcmp(sortMethod, "Dtime") == 0) {
  985.         aWindow->sortingInstructions |= FSFLAT_DTIME_SORT;
  986.     }
  987.     if (strcmp(sortMethod, "size") == 0 ||
  988.         strcmp(sortMethod, "Size") == 0) {
  989.         aWindow->sortingInstructions |= FSFLAT_SIZE_SORT;
  990.     }
  991.     }
  992.  
  993.     /* Now sort the files -- get attr's if necessary */
  994.     getAttrsP = FSFLAT_ATTR_NECESSARY_P;
  995.     if (aWindow->groupList == NULL) {
  996.     return;
  997.     }
  998.     /* need comparison function that takes ptrs to FsflatFiles */
  999.     FsflatGetCompareProc(aWindow, &compareProc, TRUE);
  1000.     for (grpPtr = aWindow->groupList; grpPtr != NULL;
  1001.         grpPtr = grpPtr->nextPtr) {
  1002.     /* if 0 or 1 files, don't sort */
  1003.     if (grpPtr->fileList == NULL || grpPtr->fileList->nextPtr == NULL) {
  1004.         continue;
  1005.     }
  1006.     for (i = 0, tmpPtr = grpPtr->fileList; tmpPtr != NULL;
  1007.         tmpPtr = tmpPtr->nextPtr, i++) {
  1008.         if (getAttrsP && tmpPtr->attrPtr == NULL) {
  1009.         tmpPtr->attrPtr = (struct stat *)
  1010.             malloc(sizeof (struct stat));
  1011.         if (lstat(tmpPtr->name, tmpPtr->attrPtr) != 0) {
  1012.             /* skip this file */
  1013.             sprintf(fsflatErrorMsg, "%s %s.",
  1014.                 "Couldn't get attributes for file", tmpPtr->name);
  1015.             Sx_Notify(fsflatDisplay, aWindow->surroundingWindow, -1, -1,
  1016.                 0, fsflatErrorMsg, NULL, TRUE, "Continue",
  1017.                 (char *) NULL);
  1018.             bzero((char *) tmpPtr->attrPtr, sizeof (struct stat));
  1019.         }
  1020.         }
  1021.     }
  1022.     arraySize = i;
  1023.     fileArray = (FsflatFile **) malloc(arraySize *
  1024.         sizeof (FsflatFile *));
  1025.     for (tmpPtr = grpPtr->fileList, i = 0; tmpPtr != NULL;
  1026.         tmpPtr = tmpPtr->nextPtr, i++) {
  1027.         fileArray[i] = tmpPtr;
  1028.     }
  1029.     qsort(fileArray, arraySize, sizeof (FsflatFile *), compareProc);
  1030.     for (i = 0; i < arraySize - 1; i++) {
  1031.         fileArray[i]->nextPtr = fileArray[i+1];
  1032.     }
  1033.     fileArray[arraySize - 1]->nextPtr = NULL;
  1034.     grpPtr->fileList = fileArray[0];
  1035.     free(fileArray);
  1036.     }
  1037.  
  1038.     return;
  1039. }
  1040.  
  1041.  
  1042.  
  1043. /*
  1044.  *----------------------------------------------------------------------
  1045.  *
  1046.  * FsflatCloseCmd --
  1047.  *
  1048.  *    Close the window.  This should do some more cleaning up.
  1049.  *
  1050.  * Syntax:
  1051.  *    close
  1052.  *
  1053.  * Results:
  1054.  *    TCL_OK.
  1055.  *
  1056.  * Side effects:
  1057.  *    Closes the window, deletes the Tcl interpreter for the window, and
  1058.  *    frees up the window data structures.  If this was the last window,
  1059.  *    we may exit.
  1060.  *
  1061.  *----------------------------------------------------------------------
  1062.  */
  1063. /*ARGSUSED*/
  1064. int
  1065. FsflatCloseCmd(aWindow, interp, argc, argv)
  1066.     register    FsflatWindow    *aWindow;
  1067.     Tcl_Interp    *interp;
  1068.     int        argc;
  1069.     char    **argv;
  1070. {
  1071.     if (!MonClient_DeleteDir(aWindow->dir,
  1072.         (ClientData) aWindow->surroundingWindow)) {
  1073.     /* what should I do here?  Does it matter? */
  1074.     }
  1075.     XDeleteContext(fsflatDisplay, aWindow->surroundingWindow,
  1076.         fsflatWindowContext);
  1077.     /* DeleteHandlers? */
  1078.     FsflatGarbageCollect(aWindow);
  1079.     XDestroyWindow(fsflatDisplay, aWindow->surroundingWindow);
  1080.     Tcl_DeleteInterp(aWindow->interp);
  1081.     free(aWindow);
  1082.     fsflatWindowCount--;
  1083.     if (fsflatWindowCount <= 0) {
  1084.     exit(0);
  1085.     }
  1086.     return TCL_OK;
  1087. }
  1088.  
  1089.  
  1090. /*
  1091.  *----------------------------------------------------------------------
  1092.  *
  1093.  * FsflatExecCmd --
  1094.  *
  1095.  *    Execute a command in an associated shell window.
  1096.  *
  1097.  * Syntax:
  1098.  *    exec command
  1099.  *
  1100.  * Results:
  1101.  *    Returns TCL_OK if all went well, or TCL_ERROR if an associated
  1102.  *    shell window could not be found or there was no shell command
  1103.  *    given.  Whether or not the command
  1104.  *    given to the shell executes happily is another matter.  Maybe I'll
  1105.  *    decide that its return status should be available, but I don't know
  1106.  *    how to do that...
  1107.  *
  1108.  * Side effects:
  1109.  *    Almost anything -- it depends what the shell command does.
  1110.  *
  1111.  *----------------------------------------------------------------------
  1112.  */
  1113. /*ARGSUSED*/
  1114. int
  1115. FsflatExecCmd(aWindow, interp, argc, argv)
  1116.     FsflatWindow    *aWindow;
  1117.     Tcl_Interp    *interp;
  1118.     int        argc;
  1119.     char    **argv;
  1120. {
  1121.     int        i;
  1122.     char    *command;
  1123.     int        length;
  1124.     int        result;
  1125.  
  1126.     length = argc;    /* spaces between command words + insert word */
  1127.     for (i = 0; i < argc; i++) {
  1128.     length += strlen(argv[i]);
  1129.     }
  1130.     length += strlen("insert");
  1131.     command = (char *) malloc(length + 1);    /* plus null char */
  1132.     strcpy(command, "insert");
  1133.     for (i = 0; i < argc; i++) {
  1134.     strcat(command, " ");
  1135.     strcat(command, argv[i]);
  1136.     }
  1137.     result = Tx_Command(fsflatDisplay, aWindow->txOutsideWindow, command);
  1138.     free(command);
  1139.  
  1140.     return result;
  1141. }
  1142.  
  1143.  
  1144. /*
  1145.  *----------------------------------------------------------------------
  1146.  *
  1147.  * FsflatGroupBindCmd --
  1148.  *
  1149.  *    Add a command binding to a group.  This will bind a command
  1150.  *    to a particular button (or button combination).
  1151.  *
  1152.  * Syntax:
  1153.  *    groupbind groupname buttonMask command
  1154.  *
  1155.  * Results:
  1156.  *    Returns TCL_OK if all went well, or TCL errors if not.
  1157.  *
  1158.  * Side effects:
  1159.  *    A new command binding will be added to the group.
  1160.  *
  1161.  *----------------------------------------------------------------------
  1162.  */
  1163. int
  1164. FsflatGroupBindCmd(aWindow, interp, argc, argv)
  1165.     FsflatWindow    *aWindow;
  1166.     Tcl_Interp        *interp;
  1167.     int            argc;
  1168.     char        **argv;
  1169. {
  1170.     FsflatGroup    *grpPtr;
  1171.     char    **buttonArgv;
  1172.     int        buttonArgc;
  1173.     int        button = 0;
  1174.     int        test;
  1175.     int        i;
  1176.  
  1177.     if (argc != 4) {
  1178.     sprintf(interp->result,
  1179.         "Wrong # of args to groupBind command, %s",
  1180.         "\"groupBind groupName buttonMask command\"");
  1181.     return TCL_ERROR;
  1182.     }
  1183.     for (grpPtr = aWindow->groupList; grpPtr != NULL;
  1184.         grpPtr = grpPtr->nextPtr) {
  1185.     if (strcmp(grpPtr->rule, argv[1]) == 0) {
  1186.         break;
  1187.     }
  1188.     }
  1189.     if (grpPtr == NULL) {
  1190.     sprintf(interp->result, "No such group %s", argv[1]);
  1191.     return TCL_ERROR;
  1192.     }
  1193.  
  1194.     if (Tcl_SplitList(interp, argv[2], &buttonArgc, &buttonArgv) != TCL_OK) {
  1195.     return TCL_ERROR;
  1196.     }
  1197.     for (i = 0; i < buttonArgc; i++) {
  1198.     test = FsflatWhichButton(buttonArgv[i]);
  1199.     if (test == 0) {
  1200.         sprintf(interp->result, "Bad button name %s", argv[i]);
  1201.         /* will this really free it?  Tcl man page says so... */
  1202.         free(buttonArgv);
  1203.         return TCL_ERROR;
  1204.     }
  1205.     button |= test;
  1206.     }
  1207.     /* will this really free it?  Tcl man page says so... */
  1208.     free(buttonArgv);
  1209.     FsflatAddGroupBinding(grpPtr, button, argv[3]);
  1210.  
  1211.     return TCL_OK;
  1212. }
  1213.  
  1214.  
  1215. /*
  1216.  *----------------------------------------------------------------------
  1217.  *
  1218.  * FsflatMenuCmd --
  1219.  *
  1220.  *    Create, delete, and modify menus.
  1221.  *
  1222.  * Syntax:
  1223.  *    menu append name leftText centerText rightText color cmd
  1224.  *    menu create name leftText centerText rightText color cmd leftText ...
  1225.  *    menu delete name
  1226.  *    menu modify name entryIndex leftText centerText rightText color cmd
  1227.  *
  1228.  * Results:
  1229.  *    Returns TCL_OK if all went well, or TCL_ERROR if any sort of
  1230.  *    error occurred.
  1231.  *
  1232.  * Side effects:
  1233.  *    The menu structure for the current window gets modified.
  1234.  *
  1235.  *----------------------------------------------------------------------
  1236.  */
  1237. int
  1238. FsflatMenuCmd(aWindow, interp, argc, argv)
  1239.     register    FsflatWindow    *aWindow;
  1240.     Tcl_Interp    *interp;
  1241.     int        argc;
  1242.     char    **argv;
  1243. {
  1244. #ifdef NOTDEF
  1245.     MxMenuInfo *miPtr;
  1246. #endif NOTDEF
  1247.     int length;
  1248.     Sx_MenuEntry entries[SX_MAX_MENU_ENTRIES];
  1249.  
  1250.     extern char *GetString();        /* Forward references */
  1251.  
  1252.     if (argc < 2) {
  1253.     sprintf(interp->result, "wrong # args: must be \"%.50s option [args]\"",
  1254.         argv[0]);
  1255.     return TCL_ERROR;
  1256.     }
  1257.     length = strlen(argv[1]);
  1258.     if (strncmp(argv[1], "append", length) == 0) {
  1259.     Window window;
  1260.     XFontStruct *fontPtr;
  1261.     int numEntries;
  1262.     unsigned long fg, bg;
  1263.  
  1264.     if (argc != 8) {
  1265.         sprintf(interp->result, "wrong # args: should be \"%.50s append name left center right color cmd\"",
  1266.             argv[0]);
  1267.         return TCL_ERROR;
  1268.     }
  1269.     window = Sx_MenuGetWindow(fsflatDisplay, aWindow->menuBar, argv[2]);
  1270.     if (window == NULL) {
  1271.         goto menuNameBad;
  1272.     }
  1273.     numEntries = Sx_MenuGetInfo(fsflatDisplay, window, entries, &fontPtr,
  1274.         &fg, &bg);
  1275.     if (numEntries >= SX_MAX_MENU_ENTRIES) {
  1276.         return TCL_OK;
  1277.     }
  1278.     entries[numEntries].leftText = GetString(argv[3]);
  1279.     entries[numEntries].centerText = GetString(argv[4]);
  1280.     entries[numEntries].rightText = GetString(argv[5]);
  1281.     entries[numEntries].background =
  1282.         Util_StringToColor(fsflatDisplay, argv[6]);
  1283. /* should check to see if it returns -1 value!!!! */
  1284.     entries[numEntries].proc = FsflatMenuProc;
  1285.     /* Mx uses a structure with both command AND aWindow fields.  Should I? */
  1286.     entries[numEntries].clientData = (ClientData) Util_Strcpy(NULL,
  1287.         argv[7]);
  1288.     Sx_MenuCreate(fsflatDisplay, aWindow->menuBar, argv[2], numEntries+1,
  1289.         entries, fontPtr, fg, bg);
  1290.     return TCL_OK;
  1291.     }
  1292.     if (strncmp(argv[1], "create", length) == 0) {
  1293.     int numEntries, i, arg;
  1294.  
  1295.     numEntries = (argc - 3)/5;
  1296.     if ((argc-3) != (numEntries*5)) {
  1297.         sprintf(interp->result, "wrong # args: should be \"%.50s create name [left center right color cmd] ...\"",
  1298.             argv[0]);
  1299.         return TCL_ERROR;
  1300.     }
  1301.     if (numEntries > SX_MAX_MENU_ENTRIES) {
  1302.         sprintf(interp->result,
  1303.             "can't create a menu with more than %d entries",
  1304.             SX_MAX_MENU_ENTRIES);
  1305.         return TCL_ERROR;
  1306.     }
  1307.  
  1308.     for (i = 0, arg = 3; i < numEntries; i++, arg += 5) {
  1309.         entries[i].leftText = GetString(argv[arg]);
  1310.         entries[i].centerText = GetString(argv[arg+1]);
  1311.         entries[i].rightText = GetString(argv[arg+2]);
  1312.         entries[i].background =
  1313.             Util_StringToColor(fsflatDisplay, argv[arg+3]);
  1314. /* should check to see if it returns -1 value! */
  1315.         entries[i].proc = FsflatMenuProc;
  1316.         entries[i].clientData = (ClientData) Util_Strcpy(NULL, argv[arg+4]);
  1317.     }
  1318.     Sx_MenuCreate(fsflatDisplay, aWindow->menuBar, argv[2], numEntries,
  1319.         entries, aWindow->fontPtr, aWindow->menuForeground,
  1320.         aWindow->menuBackground);
  1321.     return TCL_OK;
  1322.     } else if (strncmp(argv[1], "delete",length) == 0) {
  1323.     Window window;
  1324.     int count;
  1325.  
  1326.     if (argc != 3) {
  1327.         sprintf(interp->result,
  1328.             "wrong # args: should be \"%.50s delete name\"",
  1329.             argv[0]);
  1330.         return TCL_ERROR;
  1331.     }
  1332.     window = Sx_MenuGetWindow(fsflatDisplay, aWindow->menuBar, argv[2]);
  1333.     if (window == NULL) {
  1334.         goto menuNameBad;
  1335.     }
  1336.     count = Sx_MenuGetInfo(fsflatDisplay, window, entries,
  1337.         (XFontStruct **) NULL, (int *) NULL, (int *) NULL);
  1338.     for (count--; count >= 0; count--) {
  1339.         free(entries[count].clientData);
  1340.     }
  1341.     XDestroyWindow(fsflatDisplay, window);
  1342.     return TCL_OK;
  1343. #ifdef NOTDEF
  1344.     } else if (strncmp(argv[1], "info", length) == 0) {
  1345.     Window window;
  1346.     int count, i;
  1347.     char *names[SX_MAX_MENUS];
  1348.     char *entryStrings[SX_MAX_MENU_ENTRIES];
  1349.     char *pieces[4];
  1350.  
  1351.     if (argc == 2) {
  1352.         count = Sx_MenuGetNames(mxwPtr->display, mxwPtr->menuBar, names,
  1353.             (Window *) NULL);
  1354.         interp->result = Tcl_Merge(count, names);
  1355.         interp->dynamic = 1;
  1356.         return TCL_OK;
  1357.     }
  1358.     if (argc != 3) {
  1359.         sprintf(interp->result,
  1360.             "wrong # args: should be \"%.50s info [name]\"",
  1361.             argv[0]);
  1362.         return TCL_ERROR;
  1363.     }
  1364.     window = Sx_MenuGetWindow(mxwPtr->display, mxwPtr->menuBar, argv[2]);
  1365.     if (window == NULL) {
  1366.         goto menuNameBad;
  1367.     }
  1368.     count = Sx_MenuGetInfo(mxwPtr->display, window, entries,
  1369.         (XFontStruct **) NULL, (unsigned long *) NULL,
  1370.         (unsigned long *) NULL);
  1371.     for (i = 0; i < count; i++) {
  1372.         pieces[0] = entries[i].leftText;
  1373.         if (pieces[0] == NULL) {
  1374.         pieces[0] = "";
  1375.         }
  1376.         pieces[1] = entries[i].centerText;
  1377.         if (pieces[1] == NULL) {
  1378.         pieces[1] = "";
  1379.         }
  1380.         pieces[2] = entries[i].rightText;
  1381.         if (pieces[2] == NULL) {
  1382.         pieces[2] = "";
  1383.         }
  1384.         pieces[3] = ((MxMenuInfo *) entries[i].clientData)->command;
  1385.         if (pieces[3] == NULL) {
  1386.         pieces[3] = "";
  1387.         }
  1388.         entryStrings[i] = Tcl_Merge(4, pieces);
  1389.     }
  1390.     interp->result = Tcl_Merge(count, entryStrings);
  1391.     interp->dynamic = 1;
  1392.     for (i = 0; i < count; i++) {
  1393.         free(entryStrings[i]);
  1394.     }
  1395.     return TCL_OK;
  1396. #endif NOTDEF
  1397.     } else if (strncmp(argv[1], "modify", length) == 0) {
  1398.     Window window;
  1399.     Sx_MenuEntry entry;
  1400.     int index;
  1401.  
  1402.     if (argc != 9) {
  1403.         sprintf(interp->result, "wrong # args: should be \"%.50s modify name index left center right color cmd\"",
  1404.             argv[0]);
  1405.         return TCL_ERROR;
  1406.     }
  1407.     window = Sx_MenuGetWindow(fsflatDisplay, aWindow->menuBar, argv[2]);
  1408.     if (window == NULL) {
  1409.         goto menuNameBad;
  1410.     }
  1411.     index = atoi(argv[3]);
  1412.     if ((index < 0) || (index >= Sx_MenuGetInfo(fsflatDisplay, window,
  1413.         entries, (XFontStruct **) NULL, (int *) NULL, (int *) NULL))) {
  1414.         sprintf(interp->result,
  1415.             "there's no entry %d in menu \"%.50s\"",
  1416.             index, argv[2]);
  1417.         return TCL_ERROR;
  1418.     }
  1419.     free(entries[index].clientData);
  1420.     entry.leftText = GetString(argv[4]);
  1421.     entry.centerText = GetString(argv[5]);
  1422.     entry.rightText = GetString(argv[6]);
  1423. /* should check to see if it returns -1 value! */
  1424.     entry.background = Util_StringToColor(fsflatDisplay, argv[7]);
  1425.     entry.proc = FsflatMenuProc;
  1426.     entry.clientData = (ClientData) Util_Strcpy(NULL, argv[8]);
  1427.     Sx_MenuReplaceEntry(fsflatDisplay, window, index, &entry);
  1428.     return TCL_OK;
  1429.     } else {
  1430.     sprintf(interp->result, "bad \"%.50s\" option: must be append, create, delete, or modify\"",
  1431.         argv[0]);
  1432.     return TCL_ERROR;
  1433.     }
  1434.  
  1435.     menuNameBad:
  1436.     sprintf(interp->result, "there's no menu named \"%.50s\".", argv[2]);
  1437.     return TCL_ERROR;
  1438. }
  1439.  
  1440.  
  1441.  
  1442. /*
  1443.  *----------------------------------------------------------------------
  1444.  *
  1445.  * FsflatOpenCmd --
  1446.  *
  1447.  *    Create another fsflat window.
  1448.  *    Eventually this will be create another Wish window, with an
  1449.  *    argument to say whether it should be a flat or tree window.  If
  1450.  *    the argument is not supplied, it should default to the type of
  1451.  *    window where the command was called from.
  1452.  *
  1453.  * Syntax:
  1454.  *    open directory
  1455.  *
  1456.  * Results:
  1457.  *    Returns TCL_OK if all went well, various TCL errors if not.
  1458.  *
  1459.  * Side effects:
  1460.  *    A new window should be created.
  1461.  *
  1462.  *----------------------------------------------------------------------
  1463.  */
  1464. int
  1465. FsflatOpenCmd(aWindow, interp, argc, argv)
  1466.     FsflatWindow    *aWindow;
  1467.     Tcl_Interp        *interp;
  1468.     int            argc;
  1469.     char        **argv;
  1470. {
  1471.     if (argc > 2) {
  1472.     sprintf(interp->result, "%s %s", "Too many args to open command:",
  1473.         "open [directory]");
  1474.     return TCL_ERROR;
  1475.     }
  1476.     if (argc == 2) {
  1477.     if (FsflatCreate(aWindow, argv[1]) == NULL) {
  1478.         return TCL_ERROR;
  1479.     }
  1480.     } else if (FsflatCreate(aWindow, NULL) == NULL) {
  1481.     return TCL_ERROR;
  1482.     }
  1483.  
  1484.     return TCL_OK;
  1485. }
  1486.  
  1487.  
  1488. /*
  1489.  *----------------------------------------------------------------------
  1490.  *
  1491.  * FsflatPatternCompareCmd --
  1492.  *
  1493.  *    Compare two strings.  In the interpreter, return 0 for a match,
  1494.  *    and < 0 for an error.  Return > 0 for failure to match.
  1495.  *
  1496.  * Syntax:
  1497.  *    pattern    string1 string2
  1498.  *
  1499.  * Results:
  1500.  *    TCL_OK if everything went okay, TCL_ERROR if not.
  1501.  *
  1502.  * Side effects:
  1503.  *    None.
  1504.  *
  1505.  *----------------------------------------------------------------------
  1506.  */
  1507. /*ARGSUSED*/
  1508. int
  1509. FsflatPatternCompareCmd(aWindow, interp, argc, argv)
  1510.     register    FsflatWindow    *aWindow;
  1511.     Tcl_Interp    *interp;
  1512.     int        argc;
  1513.     char    **argv;
  1514. {
  1515.     int    result;
  1516.  
  1517.     if (argc != 3) {
  1518.     sprintf(interp->result, "pattern command requires 3 args");
  1519.     return TCL_ERROR;
  1520.     }
  1521.     result = Pattern_Match(argv[1], argv[2]);
  1522.     sprintf(interp->result, "%d", result);
  1523.  
  1524.     return TCL_OK;
  1525. }
  1526.  
  1527.  
  1528. /*
  1529.  *----------------------------------------------------------------------
  1530.  *
  1531.  * FsflatQuitCmd --
  1532.  *
  1533.  *    Exit the program.
  1534.  *
  1535.  * Syntax:
  1536.  *    quit
  1537.  *
  1538.  * Results:
  1539.  *    Exits.
  1540.  *
  1541.  * Side effects:
  1542.  *    Exits.
  1543.  *
  1544.  *----------------------------------------------------------------------
  1545.  */
  1546. /*ARGSUSED*/
  1547. int
  1548. FsflatQuitCmd(aWindow, interp, argc, argv)
  1549.     register    FsflatWindow    *aWindow;
  1550.     Tcl_Interp    *interp;
  1551.     int        argc;
  1552.     char    **argv;
  1553. {
  1554.     /*
  1555.      * I should go through and call MonClient_DeleteDir for each remaining 
  1556.      * window.
  1557.      */
  1558.     exit(0);
  1559. }
  1560.  
  1561. #ifdef NOTDEF
  1562.  
  1563. /*
  1564.  *----------------------------------------------------------------------
  1565.  *
  1566.  * FsflatRestartCmd --
  1567.  *
  1568.  *    Resource the startup files and rebuild the display of the current
  1569.  *    directory.
  1570.  *
  1571.  * Syntax:
  1572.  *    restart
  1573.  *
  1574.  * Results:
  1575.  *    Returns TCL_OK if all went well, or TCL_ERROR if any sort of
  1576.  *    error occurred.
  1577.  *
  1578.  * Side effects:
  1579.  *    The display may change if the startup files have changed.
  1580.  *
  1581.  *----------------------------------------------------------------------
  1582.  */
  1583. int
  1584. FsflatRestartCmd(aWindow, interp, argc, argv)
  1585.     FsflatWindow    *aWindow;
  1586.     int            argc;
  1587.     char        **argv;
  1588. {
  1589.     if (argc != 1) {
  1590.     sprintf(interp->result, "too many args to restart command. 1 arg max");
  1591.     return TCL_ERROR;
  1592.     }
  1593.     FsflatGarbageCollect(aWindow);
  1594.     /* delete interpreter and start new one? */
  1595.     if (FsflatGatherNames(aWindow) != TCL_OK) {
  1596.     /* Fix here too. */
  1597.     }
  1598.     /* should it repick the size here if aWindow->pickSizeP is true? */
  1599.     aWindow->firstElement = 1;
  1600.     FsflatSetPositions(aWindow);
  1601.     /* FsflatRedraw will be called from event caused in FsflatSetPositions() */
  1602.  
  1603.     return TCL_OK;
  1604. }
  1605. #endif NOTDEF
  1606.  
  1607.  
  1608. /*
  1609.  *----------------------------------------------------------------------
  1610.  *
  1611.  * FsflatRedrawCmd --
  1612.  *
  1613.  *    Redraw the window.
  1614.  *
  1615.  * Syntax:
  1616.  *    redraw
  1617.  *
  1618.  * Results:
  1619.  *    TCL_OK.
  1620.  *
  1621.  * Side effects:
  1622.  *    Redraws the window.
  1623.  *
  1624.  *----------------------------------------------------------------------
  1625.  */
  1626. /*ARGSUSED*/
  1627. int
  1628. FsflatRedrawCmd(aWindow, interp, argc, argv)
  1629.     register    FsflatWindow    *aWindow;
  1630.     Tcl_Interp    *interp;
  1631.     int        argc;
  1632.     char    **argv;
  1633. {
  1634.     if (aWindow->dontDisplayChangesP == FALSE) {
  1635.     FsflatRedraw(aWindow);
  1636.     }
  1637.     return TCL_OK;
  1638. }
  1639.  
  1640.  
  1641. /*
  1642.  *----------------------------------------------------------------------
  1643.  *
  1644.  * FsflatResizeCmd --
  1645.  *
  1646.  *    Resize the window.
  1647.  *
  1648.  * Syntax:
  1649.  *    redraw newheight newwidth
  1650.  *
  1651.  * Results:
  1652.  *    TCL_OK if everything goes well, TCL_ERROR if not.
  1653.  *
  1654.  * Side effects:
  1655.  *    Resizes the window.
  1656.  *
  1657.  *----------------------------------------------------------------------
  1658.  */
  1659. int
  1660. FsflatResizeCmd(aWindow, interp, argc, argv)
  1661.     register    FsflatWindow    *aWindow;
  1662.     Tcl_Interp    *interp;
  1663.     int        argc;
  1664.     char    **argv;
  1665. {
  1666.     int    height, width;
  1667.     char    *cptr;
  1668.  
  1669.     if (argc != 3) {
  1670.     sprintf(interp->result, "Wrong # of args to resize command: %s",
  1671.         "\"resize newheight newwidth\"");
  1672.     return TCL_ERROR;
  1673.     }
  1674.     if ((height = strtol(argv[1], &cptr, 10)) == 0 && cptr == argv[1]) {
  1675.     sprintf(interp->result, "Bad height arg to resize command: %s",
  1676.         argv[1]);
  1677.     return TCL_ERROR;
  1678.     }
  1679.     if ((width = strtol(argv[2], &cptr, 10)) == 0 && cptr == argv[2]) {
  1680.     sprintf(interp->result, "Bad width arg to resize command: %s", argv[2]);
  1681.     return TCL_ERROR;
  1682.     }
  1683.     
  1684.     FsflatSetWindowAndRowInfo(aWindow, height, width);
  1685.  
  1686.     if (aWindow->dontDisplayChangesP == FALSE) {
  1687.     /* update display */
  1688.     if (aWindow->firstElement == UNINITIALIZED) {
  1689.         aWindow->firstElement = 1;
  1690.     }
  1691.     FsflatSetPositions(aWindow);
  1692.     /*
  1693.      * FsflatRedraw will be called from event caused in FsflatSetPostions().
  1694.      */
  1695.     }
  1696.  
  1697.     return TCL_OK;
  1698. }
  1699.  
  1700.  
  1701. /*
  1702.  *----------------------------------------------------------------------
  1703.  *
  1704.  * FsflatToggleSelEntryCmd --
  1705.  *
  1706.  *    Toggle the selection status of the given entry.
  1707.  *
  1708.  * Syntax:
  1709.  *    toggleSelectionEntry x y [wholeLine]
  1710.  *
  1711.  * Results:
  1712.  *    TCL_OK if everything went well.  TCL_ERROR if not.
  1713.  *
  1714.  * Side effects:
  1715.  *    Toggles the chosen entry.
  1716.  *
  1717.  *----------------------------------------------------------------------
  1718.  */
  1719. /*ARGSUSED*/
  1720. int
  1721. FsflatToggleSelEntryCmd(aWindow, interp, argc, argv)
  1722.     register    FsflatWindow    *aWindow;
  1723.     Tcl_Interp    *interp;
  1724.     int        argc;
  1725.     char    **argv;
  1726. {
  1727.     int        x, y;
  1728.     FsflatFile    *filePtr;
  1729.     FsflatGroup    *groupPtr = NULL;
  1730.     int    lineP = 0;
  1731.     char    *cptr;
  1732.  
  1733.     if (argc < 3 || argc > 4) {
  1734.     sprintf(aWindow->interp->result, "Wrong # of args to toggleSelection");
  1735.     return TCL_ERROR;
  1736.     }
  1737.     if ((x = strtol(argv[1], &cptr, 10)) == 0 && cptr == argv[1]) {
  1738.     sprintf(aWindow->interp->result, "Bad window x coordinate %s", argv[1]);
  1739.     return TCL_ERROR;
  1740.     }
  1741.     if ((y = strtol(argv[2], &cptr, 10)) == 0 && cptr == argv[2]) {
  1742.     sprintf(aWindow->interp->result, "Bad window y coordinate %s", argv[2]);
  1743.     return TCL_ERROR;
  1744.     }
  1745.     if (argc == 4) {
  1746.     if ((lineP = strtol(argv[3], &cptr, 10)) == 0 && cptr == argv[3]) {
  1747.         sprintf(aWindow->interp->result, "Bad 3rd arg to toggleSelection");
  1748.         return TCL_ERROR;
  1749.     }
  1750.     }
  1751.     
  1752.     filePtr = FsflatMapCoordsToFile(aWindow, x, y);
  1753.     if (filePtr == NULL && groupPtr == NULL) {
  1754.     sprintf(aWindow->interp->result,
  1755.         "No entry to select at those coordinates: %d %d", x, y);
  1756.     return TCL_ERROR;
  1757.     }
  1758.     if (filePtr != NULL) {
  1759.     FsflatChangeSelection(aWindow, (ClientData) filePtr, TRUE, lineP, TRUE);
  1760.     } else {
  1761.     FsflatChangeSelection(aWindow, (ClientData) groupPtr, FALSE, FALSE,
  1762.         TRUE);
  1763.     }
  1764.  
  1765.     return TCL_OK;
  1766. }
  1767.  
  1768. /*
  1769.  *----------------------------------------------------------------------
  1770.  *
  1771.  * FsflatToggleSelectionCmd --
  1772.  *
  1773.  *    Select or deselect given file.
  1774.  *
  1775.  * Syntax:
  1776.  *    toggleSelection x y [wholeLine]
  1777.  *
  1778.  * Results:
  1779.  *    TCL_OK if everything went well.  TCL_ERROR if not.
  1780.  *
  1781.  * Side effects:
  1782.  *    Changes the selection variable to be given file or empty.
  1783.  *
  1784.  *----------------------------------------------------------------------
  1785.  */
  1786. int
  1787. FsflatToggleSelectionCmd(aWindow, interp, argc, argv)
  1788.     register    FsflatWindow    *aWindow;
  1789.     Tcl_Interp    *interp;
  1790.     int        argc; char    **argv;
  1791. {
  1792.     int        x, y;
  1793.     FsflatFile    *filePtr = NULL;
  1794.     FsflatGroup    *groupPtr = NULL;        /* not used yet */
  1795.     int    lineP = 0;
  1796.     char    *cptr;
  1797.  
  1798.     if (argc < 3 || argc > 4) {
  1799.     sprintf(aWindow->interp->result, "Wrong # of args to toggleSelection");
  1800.     return TCL_ERROR;
  1801.     }
  1802.     if ((x = strtol(argv[1], &cptr, 10)) == 0 && cptr == argv[1]) {
  1803.     sprintf(aWindow->interp->result, "Bad window x coordinate %s", argv[1]);
  1804.     return TCL_ERROR;
  1805.     }
  1806.     if ((y = strtol(argv[2], &cptr, 10)) == 0 && cptr == argv[2]) {
  1807.     sprintf(aWindow->interp->result, "Bad window y coordinate %s", argv[2]);
  1808.     return TCL_ERROR;
  1809.     }
  1810.     if (argc == 4) {
  1811.     if ((lineP = strtol(argv[3], &cptr, 10)) == 0 && cptr == argv[3]) {
  1812.         sprintf(aWindow->interp->result, "Bad 3rd arg to toggleSelection");
  1813.         return TCL_ERROR;
  1814.     }
  1815.     }
  1816.     
  1817.     filePtr = FsflatMapCoordsToFile(aWindow, x, y);
  1818.     if (filePtr == NULL && groupPtr == NULL) {
  1819.     sprintf(aWindow->interp->result,
  1820.         "No entry to select at those coordinates: %d %d", x, y);
  1821.     return TCL_ERROR;
  1822.     }
  1823.     if (filePtr != NULL) {
  1824.     FsflatChangeSelection(aWindow, (ClientData) filePtr, TRUE, lineP,
  1825.         FALSE);
  1826.     } else {
  1827.     FsflatChangeSelection(aWindow, (ClientData) groupPtr, FALSE, FALSE,
  1828.         FALSE);
  1829.     }
  1830.  
  1831.     return TCL_OK;
  1832. }
  1833.  
  1834. void
  1835. FsflatCmdTableInit(cmdTablePtr, interpPtr, commands, clientData)
  1836.     Cmd_Table    *cmdTablePtr;
  1837.     Tcl_Interp    **interpPtr;
  1838.     CmdInfo    commands[];
  1839.     ClientData    clientData;
  1840. {
  1841.     CmdInfo    *cmd;
  1842.     int        i;
  1843.  
  1844.     *cmdTablePtr = Cmd_TableCreate();
  1845.     *interpPtr = Tcl_CreateInterp(); 
  1846.     for (cmd = commands; cmd->name != NULL; cmd++) {
  1847.     Tcl_CreateCommand(*interpPtr, cmd->name, cmd->proc, clientData,
  1848.         (void (*)()) NULL);
  1849.     }
  1850.     for (i = insertFirst; i <= insertLast; i++) {
  1851.     char    string[2];
  1852.  
  1853.     string[0] = i;
  1854.     string[1] = 0;
  1855.     Cmd_BindingCreate(*cmdTablePtr, string, "!@");
  1856.     }
  1857.  
  1858.     return;
  1859. }
  1860.  
  1861.  
  1862. /*
  1863.  *----------------------------------------------------------------------
  1864.  *
  1865.  * FsflatAddGroupBinding --
  1866.  *
  1867.  *    Add a command binding to a file group.
  1868.  *
  1869.  * Results:
  1870.  *    None.
  1871.  *
  1872.  * Side effects:
  1873.  *    New command binding added to given group.
  1874.  *
  1875.  *----------------------------------------------------------------------
  1876.  */
  1877. void
  1878. FsflatAddGroupBinding(grpPtr, button, command)
  1879.     FsflatGroup        *grpPtr;
  1880.     int            button;            /* button binding */
  1881.     char        *command;
  1882. {
  1883.     FsflatGroupBinding    *bPtr;
  1884.  
  1885.     for (bPtr = grpPtr->groupBindings; bPtr != NULL; bPtr = bPtr->nextPtr) {
  1886.     if (bPtr->button == button) {
  1887.         /* substitute command and return */
  1888.         if (bPtr->command != NULL) {
  1889.         free(bPtr->command);
  1890.         }
  1891.         bPtr->command = Util_Strcpy(NULL, command);
  1892.         return;
  1893.     }
  1894.     }
  1895.     /* Not there already */
  1896.     bPtr = (FsflatGroupBinding *) malloc(sizeof (FsflatGroupBinding));
  1897.     bPtr->button = button;
  1898.     bPtr->command = Util_Strcpy(NULL, command);
  1899.     bPtr->nextPtr = grpPtr->groupBindings;
  1900.     grpPtr->groupBindings = bPtr;
  1901.  
  1902.     return;
  1903. }
  1904.  
  1905. void
  1906. FsflatDeleteGroupBindings(grpPtr)
  1907.     FsflatGroup    *grpPtr;
  1908. {
  1909.     FsflatGroupBinding    *bPtr, *nPtr;
  1910.  
  1911.     for (bPtr = grpPtr->groupBindings; bPtr != NULL; ) {
  1912.     nPtr = bPtr->nextPtr;
  1913.     free(bPtr->command);
  1914.     free(bPtr);
  1915.     bPtr = nPtr;
  1916.     }
  1917.     grpPtr->groupBindings = NULL;
  1918.  
  1919.     return;
  1920. }
  1921.  
  1922. void
  1923. FsflatDeleteGroupBinding(grpPtr, button)
  1924.     FsflatGroup    *grpPtr;
  1925.     int        button;
  1926. {
  1927.     FsflatGroupBinding    *bPtr, *nPtr;
  1928.  
  1929.     if (grpPtr->groupBindings == NULL) {
  1930.     return;
  1931.     }
  1932.     if (grpPtr->groupBindings->button == button) {
  1933.     bPtr = grpPtr->groupBindings;
  1934.     grpPtr->groupBindings = grpPtr->groupBindings->nextPtr;
  1935.     free(bPtr->command);
  1936.     free(bPtr);
  1937.  
  1938.     return;
  1939.     }
  1940.     for (bPtr = grpPtr->groupBindings; bPtr->nextPtr != NULL;
  1941.         bPtr = bPtr->nextPtr ) {
  1942.     nPtr = bPtr->nextPtr;
  1943.     if (nPtr->button == button) {
  1944.         bPtr->nextPtr = nPtr->nextPtr;
  1945.         free(nPtr->command);
  1946.         free(nPtr);
  1947.         return;
  1948.     }
  1949.     }
  1950.  
  1951.     return;
  1952. }
  1953.  
  1954.  
  1955.  
  1956. char *
  1957. FsflatGetGroupBinding(grpPtr, button)
  1958.     FsflatGroup    *grpPtr;
  1959.     int        button;
  1960. {
  1961.     FsflatGroupBinding    *bPtr;
  1962.  
  1963.     for (bPtr = grpPtr->groupBindings; bPtr != NULL; bPtr = bPtr->nextPtr) {
  1964.     if (bPtr->button == button) {
  1965.         break;
  1966.     }
  1967.     }
  1968.     if (bPtr == NULL) {
  1969.     return NULL;
  1970.     }
  1971.     return bPtr->command;
  1972. }
  1973.  
  1974.  
  1975.  
  1976. /*
  1977.  *----------------------------------------------------------------------
  1978.  *
  1979.  * FsflatDoCmd --
  1980.  *
  1981.  *    Execute a given Tcl command in a given window, and display
  1982.  *    error information if the command doesn't complete successfully.
  1983.  *
  1984.  * Results:
  1985.  *    Returns the result code from the command: TCL_OK, etc.
  1986.  *
  1987.  * Side effects:
  1988.  *    Can be almost arbitrary, depending on the command.
  1989.  *
  1990.  *----------------------------------------------------------------------
  1991.  */
  1992. int
  1993. FsflatDoCmd(aWindow, command)
  1994.     FsflatWindow    *aWindow;
  1995.     char    *command;
  1996. {
  1997.     int        result;
  1998.  
  1999.     result = Tcl_Eval(aWindow->interp, command, 0, (char **) 0);
  2000.     if (result == TCL_OK) {
  2001. #ifdef NOTDEF
  2002.     if (*aWindow->interp->result != 0) {
  2003. /* this won't work with close command, interpreter and window structure gone! */
  2004.         /*
  2005.          * output message - should call routine that uses 1-line window
  2006.          * if possible.
  2007.          */
  2008.     }
  2009. #endif NOTDEF
  2010.     return result;
  2011.     }
  2012.  
  2013.     FsflatPrintTclError(aWindow);
  2014.  
  2015.     return result;
  2016. }
  2017.  
  2018.  
  2019. /*
  2020.  * Local procedure used to turn empty or "-" strings into NULLs.
  2021.  */
  2022. static char *
  2023. GetString(string)
  2024.     char *string;
  2025. {
  2026.     if ((string[0] == 0) || ((string[0] == '-') && (string[1] == 0))) {
  2027.     return NULL;
  2028.     }
  2029.     return string;
  2030. }
  2031.  
  2032. int
  2033. FsflatWhichButton(token)
  2034.     char    *token;
  2035. {
  2036.  
  2037.     if (strcmp(token, "Left") == 0 ||
  2038.         strcmp(token, "left") == 0) {
  2039.     return FSFLAT_LEFT_BUTTON;
  2040.     }
  2041.     if (strcmp(token, "Middle") == 0 ||
  2042.         strcmp(token, "middle") == 0) {
  2043.     return FSFLAT_MIDDLE_BUTTON;
  2044.     }
  2045.     if (strcmp(token, "Right") == 0 ||
  2046.         strcmp(token, "right") == 0) {
  2047.     return FSFLAT_RIGHT_BUTTON;
  2048.     }
  2049.     if (strcmp(token, "Meta") == 0 ||
  2050.         strcmp(token, "meta") == 0) {
  2051.     return FSFLAT_META_BUTTON;
  2052.     }
  2053.     if (strcmp(token, "Shift") == 0 ||
  2054.         strcmp(token, "shift") == 0) {
  2055.     return FSFLAT_SHIFT_BUTTON;
  2056.     }
  2057.     return 0;
  2058. }
  2059.